#ifndef __JOIN_DISK__
#define __JOIN_DISK__
#pragma once
#include "Disk.h"
#include <list>
#include "SortTests.h"

class JoinTests
{
public:
	JoinTests(void);
	~JoinTests(void);


	void PreTest(wstring wsRel1FileNameFlash, wstring wsRel2FileNameFlash,wstring wsResFileNameFlash/*,
					wstring wsRel1FileNameDisk, wstring wsRel2FileNameDisk*/);
	void PerformTest(ostream& fResults, int nIteration); 
	void PostTest();

	static int nBufferLimitedByteCount;
	static int nSmallRelByteCount;
	static int nBigRelByteCount;



private:
	bool CreateRandomRelations(	float fColumnCDensity1, 
					   float fColumnCDensity2, int nRel1RowsNum, int nRel2RowsNum, int nRel1ByteCount, 
					   int nRel2ByteCount, wstring wsRel1FileNameFlash, wstring wsRel2FileNameFlash);

	bool CreateRandomRelations2(	float fColumnCDensity1, 
					   float fColumnCDensity2, int nRel1RowsNum, int nRel2RowsNum, int nRel1ByteCount, 
					   int nRel2ByteCount, wstring wsRel1FileNameFlash, wstring wsRel2FileNameFlash,int nNumOfSortedBlocks);

	bool CreateRel2SortedParts(	int nNumberOfSortedParts, int nRel2RowsNum, int nRel2ByteCount, wstring wsRel2FileNameFlash);


	bool CreateRandomRelations1( float fSmallRelationDencity, int nNumOfJoinRows, int nBigRelRowsNum, 
									int nSmallRelRowsNum, int nBigRelByteCount, 
									int nSmallRelByteCount, wstring wsBigRelFileName, wstring wsSmallRelFileName);
	bool CreateAlmostSortedRelation(float fUnsortedRatio, int nRel2RowsNum, 
					int nRel2ByteCount, wstring wsRel2FileNameFlash);



	int	GetRandNum(int nLow, int nHigh);

	bool AllocateVirtualBuffer(void** pBuffer, int nBytesCount);
	bool DeAllocateVirtualBuffer(void** pBuffer, int nBytesCount);
	BOOL GetLogicalDiskPhysicalInfo(wstring wDiskName);
	bool NestedLoopJoin(wstring wsRel1FileName, wstring wsRel2FileName, wstring wsResFileName, float& rfTimeSec, 
						int& rnMatchesNum, int& rnReadSectorsNum);
	bool OffsetHashJoin(wstring wsRel1FileName, wstring wsRel2FileName,
						wstring wsHashFileName, float fColumnCDensity,
						float& rfTimeSec, int nNumberOfWords, int& rnReadSectorsNum);

	bool SortedBlockJoin(wstring wsRel1FileName, wstring wsRel2FileName,
					wstring wsHashFileName, wstring wsSortedFileName, wstring wsRsFileName, bool bUseRs, float fColumnCDensity,
					float& rfTimeSec, int nNumOfWords, int& rnReadSectorsNum, ESortType eSortType);

	bool CreateOffsetHash( wstring wsRel1FileName, wstring wsHashFileName, 
							float fColumnCDensity, int &nHashWords, float& rfTimeSec);

	bool OffsetHashJoin1( wstring wsRel1FileName, wstring wsRel2FileName,
							wstring wsHashFileName, float fColumnCDensity,
							int nNumberOfWords, float& rfTimeSec, int& rnReadSectorsNum, ESortType eSortType);

	bool SortedBlockLocalJoin(	wstring wsRel1FileName, wstring wsRel2FileName,
								wstring wsHashFileName, wstring wsSortedFileName, wstring wsRsFileName, bool bUseRs,
								float fColumnCDensity, float& rfTimeSec,  int& rnReadSectorsNum, ESortType eSortType);

	bool OffsetHashJoin2(wstring wsRel1FileName, wstring wsRel2FileName,
							wstring wsHashFileName, float fColumnCDensity,
							int nNumberOfWords, float& rfTimeSec,  int& rnReadSectorsNum, ESortType eSortType);

	void PrintResults(ostream& fResults, float fTimeSec, int nReadSectorsNum);

	//template <class T>
	//bool CreateBlockSortedRelation( wstring wsRelFileName, wstring wsSortedFileName,  wstring wsRsFileName, 
	//								int nRelRowsNum, int nRelByteCount, float& rfTimeSec, int& rnReadSectorsNum, int& rnWrittenSectorsNum, 
	//								bool bUseRs);

	template <class T>
	void MergeSort(int nLow,int nHigh, T* psRel, T* psRelSorted);

	template <class T>
	void Merge(int nLow,int nMid,int nHigh, T* psRel, T* psRelSorted);

	template <class T>
	void QuickSort(T arr[], int nBegInd, int nEndInd);

	template <class T>
	bool FindElemInHash(T* psRelBuffer, int* pnColHash, int nIndex, int nWordsCount, int nHeaderSize,
							   int& nOffsetsNum, int& nElem, int& nOffsetIndex);

	template <class T>
	void PerformRS( wstring wsRelFileName, wstring wsRSFileName,
					int nRelRowsNum, int nRelByteCount, float& rfTimeSec, int& rnReadSectorsNum);

	template <class T>
	void FindSmallerElement(T* psRelBuffer, int nIndex, int nWordsCount, int nTotalWordsCount, T lastElement);

	template<class T> 
	void ListinsertSort(T * v, int n);


	void CheckForRunEnd(int& rnRSIndex, int nNumOfLinesInBlock, DWORDLONG& rdwlRSOffset, void* psRelRSdBuffer, Disk* psDiskRSdRel, bool bForceWrite);
	void CheckForBufferRead(int& rnIndex, int nNumOfLinesInBlock, DWORDLONG& rdwlOffset, Disk* psDiskRel, void* psRelBuffer, DWORDLONG dwlBarrierOffset);

	void Test1(ostream& fResults, int nIteration);
	void Test2(ostream& fResults, int nIteration);
	void Test3(ostream& fResults, int nIteration);

	//template <class T>
	//bool SortInIterations(int nCurrIteration, int nTotalNumOfIterations, wstring wsRelFileName, wstring wsSortedFileName, int nRelRowsNum,
	//						int nRelByteCount, float& rfTimeSec, int& rnReadSectorsNum, int& rnWrittenSectorsNum, wstring& rwsFinalFileName);

	void SortingUnitTest();

	//template <class T>
	//bool SortInBlocks(wstring wsRelFileName, wstring wsSortedFileName, int nRelRowsNum,
	//					int nRelByteCount, float& rfTimeSec, int& rnReadSectorsNum, int& rnWrittenSectorsNum);

	//template <class T>
	//bool MergeSortKs(wstring wsRelFileName, wstring wsSortedFileName, int nRelRowsNum,
	//					int nRelByteCount, float& rfTimeSec, int& rnReadSectorsNum, int& rnWrittenSectorsNum);

	//template <class T>
	//bool InsertToResultList(T* pNewElem, list<T>* pSmallersList);

	//template <class T>
	//bool MergeSortKsV1(wstring wsRelFileName, wstring wsSortedFileName, int nRelRowsNum,
	//					int nRelByteCount, float& rfTimeSec, int& rnReadSectorsNum, int& rnWrittenSectorsNum);

	//template <class T>
	//bool MergeSortKsV2(wstring wsRelFileName, wstring wsSortedFileName, int nRelRowsNum,
	//					int nRelByteCount, float& rfTimeSec, int& rnReadSectorsNum, int& rnWrittenSectorsNum);


	inline float CalcTime(DWORD dwStart, DWORD dwStop);

	SRel1* m_psRel1Buffer;
	SRel2* m_psRel2Buffer;

	// Logical drive physical information
	DWORD		m_dwSectPerClust;
    DWORD		m_dwBytesPerSect;
    DWORD		m_dwFreeClusters;
    DWORD		m_dwTotalClusters;

	// Relations data
	int m_nRel1RowsNum;
	int m_nRel2RowsNum;
	int m_nRel1ByteCount;
	int m_nRel2ByteCount;

	// Files names
	wstring m_wsRel1FileNameFlash;
	wstring m_wsRel2FileNameFlash;
	wstring m_wsResFileNameFlash;
	wstring m_wsRel1FileNameDisk;
	wstring m_wsRel2FileNameDisk;



	CSortTests*	m_pSortTests;
};

#endif // __JOIN_DISK__